#include "QPcapPacket.h"

QPcapPacket::QPcapPacket(QObject *parent) : QObject(parent){
    sourceAddress = new QHostAddress();
    sourcePort = 0;
    destinationAddress = new QHostAddress();
    destinationPort = 0;
    data = new QByteArray();
    protocol = 0;
}


QPcapPacket::QPcapPacket(QHostAddress * sourceAddress, int sourcePort, QHostAddress * destinationAddress, int destinationPort, QByteArray  * data, QObject *parent) : QObject(parent){
    this -> sourceAddress = sourceAddress;
    this -> sourcePort = sourcePort;
    this -> destinationAddress = destinationAddress;
    this -> destinationPort = destinationPort;
    this -> data = data;
}


QPcapPacket::QPcapPacket(unsigned char * dataGram, QObject *parent) : QObject(parent){
    IpHeader * ipHeader;
    UdpHeader * udpHeader;
    int ipLength;

    QString sourceAddressString = QString();
    QString destinationAddressString = QString();

    /* Retrieve the position of the ip header */
    ipHeader = (IpHeader *) (dataGram + 14); //length of ethernet header
    ipLength = QPcapPacket::getIpLengthFromVersion(ipHeader -> VersionAndHeaderLength);
    udpHeader = (UdpHeader *) ((unsigned char *)ipHeader + ipLength);

    this -> protocol = (int)ipHeader -> protocol;
    this -> sourcePort = QPcapPacket::invertBitsOrder(udpHeader -> sourcePort);
    this -> destinationPort = QPcapPacket::invertBitsOrder(udpHeader->destinationPort);

    sourceAddressString.append(QString::number((int) ipHeader -> saddr.byte1)).append('.').append(QString::number((int) ipHeader -> saddr.byte2)).append('.').append(QString::number((int) ipHeader -> saddr.byte3)).append('.').append(QString::number((int) ipHeader -> saddr.byte4));
    destinationAddressString.append(QString::number((int) ipHeader -> daddr.byte1)).append('.').append(QString::number((int) ipHeader -> daddr.byte2)).append('.').append(QString::number((int) ipHeader -> daddr.byte3)).append('.').append(QString::number((int) ipHeader -> daddr.byte4));

    this -> sourceAddress = new QHostAddress(sourceAddressString);
    this -> destinationAddress = new QHostAddress(destinationAddressString);

    this -> data = new QByteArray((char *) udpHeader + sizeof(UdpHeader), QPcapPacket::invertBitsOrder(udpHeader -> len) - sizeof(UdpHeader));
    this -> checksum = qChecksum(data->data(), data->size());

}


QPcapPacket::~QPcapPacket(){
    delete this->destinationAddress;
    delete this->sourceAddress;
    delete this->data;
}




int QPcapPacket::getProtocol(){
    return this -> protocol;
}




int QPcapPacket::getIpLengthFromVersion(unsigned char version){
    unsigned char ipLength = version;
    ipLength = ipLength & 0xF;  //Retain lower 4 bits

    if (ipLength > 5)
        ipLength++;
    return (((int) ipLength) * 32) / 8;
}



QByteArray QPcapPacket::invertBitsOrder(const QByteArray array){
    QByteArray newArray = QByteArray();
    newArray.resize(2);
    for (int i = 0; i < array.size(); i++){
        newArray[array.size() - i - 1] = array[i];
    }
    return newArray;
}

unsigned short QPcapPacket::invertBitsOrder(const unsigned short number){
    unsigned short newNumber;
    int size = sizeof(number);
    for (int i = 0; i < size; i ++){
        ((char*)(&newNumber))[i] = ((char *)(&number))[size - 1 - i];
    }
    return newNumber;
}






QByteArray * QPcapPacket::getData(){
    return this -> data;
}


unsigned short QPcapPacket::getChecksum(){
    return this->checksum;
}

unsigned short QPcapPacket::getOpCode(){
    if (this->data->size() < 8)
        return 0;

    /*
    unsigned char  opCode[2];
    opCode[0] = data -> at(6);
    opCode[1] = data -> at(7);

    return *((unsigned short *) opCode);
    */
    return (unsigned short)((quint8) data -> at(6));
}


unsigned short QPcapPacket::getSourcePort(){
    return this -> sourcePort;
}


unsigned short QPcapPacket::getDestinationPort(){
    return this -> destinationPort;
}

QHostAddress * QPcapPacket::getSourceAddress(){
    return this -> sourceAddress;
}


QHostAddress * QPcapPacket::getDestinationAddress(){
    return this -> destinationAddress;
}

QString QPcapPacket::dataToString(int maxLength){
    QString string = QString();
    for (int i = 0; i < this -> data -> length() && i < maxLength; i++){
        unsigned char chiffre = (unsigned char) data -> at(i);
        QString temp = QString(QByteArray::number(chiffre, 16));
        if (temp.length() == 1)
            temp = '0'+temp;
        string.append(temp + " ");
    }
    return string;
}


QString QPcapPacket::toString(){
    QString sourceAddressString = QString();
    QString destinationAddressString = QString();

    sourceAddressString = this -> sourceAddress -> toString() + ":" + QString::number(this->sourcePort);
    destinationAddressString = this -> destinationAddress -> toString() + ":" + QString::number(this->destinationPort);

    return "(Data Size:" + QString::number(this -> data -> size()) + ") <font color=#8800ff>" +
            sourceAddressString + "    =>    " + destinationAddressString +
            "</font>, OpCode : " + QString::number(this -> getOpCode()) +
            ", Checksum : " + QString::number(this -> checksum) +
            "<br/>   Data : <i><font color=#777777>" + this -> dataToString() + "</font></i>";
}
